import tkinter as tk
from tkinter import ttk, messagebox, font
from datetime import datetime
import csv
import os
from tkcalendar import Calendar  # 添加日历控件


class AccountingApp:
    def __init__(self, root):
        self.root = root
        self.root.title("个人记账本")
        self.root.geometry("900x650")
        self.root.resizable(True, True)
        self.root.configure(bg="white")

        # 创建自定义字体
        self.title_font = font.Font(family="Microsoft YaHei", size=14, weight="bold")
        self.header_font = font.Font(family="Microsoft YaHei", size=11, weight="bold")
        self.base_font = font.Font(family="Microsoft YaHei", size=10)
        self.mono_font = font.Font(family="Consolas", size=10)

        # 创建CSV文件（如果不存在）
        self.filename = "accounting_records.csv"
        self.create_csv_file()

        # 创建主框架
        self.main_frame = ttk.Frame(root)
        self.main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)

        # 创建标签页
        self.notebook = ttk.Notebook(self.main_frame)
        self.notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 记账标签页
        self.record_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.record_frame, text="记账")
        self.create_record_tab()

        # 查账标签页
        self.query_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.query_frame, text="查账")
        self.create_query_tab()

        # 关于标签页
        self.about_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.about_frame, text="关于")
        self.create_about_tab()

    def create_csv_file(self):
        """创建CSV文件并添加表头（如果文件不存在）"""
        if not os.path.exists(self.filename):
            with open(self.filename, 'w', newline='', encoding='utf-8') as file:
                writer = csv.writer(file)
                writer.writerow(["时间", "类型", "分类", "金额", "事项"])

    def create_record_tab(self):
        """创建记账标签页"""
        # 创建主框架
        record_main_frame = ttk.Frame(self.record_frame)
        record_main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 左侧输入面板
        input_frame = ttk.LabelFrame(record_main_frame, text="添加新记录")
        input_frame.grid(row=0, column=0, padx=5, pady=5, sticky=tk.NSEW)

        # 右侧最近记录面板
        recent_frame = ttk.LabelFrame(record_main_frame, text="最近记录")
        recent_frame.grid(row=0, column=1, padx=5, pady=5, sticky=tk.NSEW)

        # 配置行列权重使内容自适应
        record_main_frame.columnconfigure(0, weight=1)
        record_main_frame.columnconfigure(1, weight=1)
        record_main_frame.rowconfigure(0, weight=1)

        # 输入表单布局优化
        container_frame = ttk.Frame(input_frame)
        container_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 标签与输入框设置
        labels = ["日期:", "类型:", "分类:", "金额:", "事项:"]
        for i, label_text in enumerate(labels):
            ttk.Label(container_frame, text=label_text, font=self.base_font).grid(
                row=i, column=0, padx=5, pady=5, sticky=tk.W)

        # 日期输入（使用日历控件）
        date_frame = ttk.Frame(container_frame)
        date_frame.grid(row=0, column=1, padx=5, pady=5, sticky=tk.EW)

        # 创建日历弹出按钮
        self.date_var = tk.StringVar(value=datetime.now().strftime("%Y-%m-%d"))
        self.date_entry = ttk.Entry(date_frame, textvariable=self.date_var, font=self.base_font, width=12)
        self.date_entry.pack(side=tk.LEFT, padx=(0, 5), fill=tk.X, expand=True)

        # 添加日期选择按钮
        date_btn = ttk.Button(date_frame, text="选择日期", width=8,
                              command=self.show_date_calendar)
        date_btn.pack(side=tk.RIGHT)

        # 类型选择
        self.type_var = tk.StringVar(value="支出")
        type_combobox = ttk.Combobox(container_frame, textvariable=self.type_var, font=self.base_font,
                                     values=["收入", "支出"], state="readonly")
        type_combobox.grid(row=1, column=1, padx=5, pady=5, sticky=tk.EW)

        # 分类选择
        self.category_var = tk.StringVar(value="生活")
        category_combobox = ttk.Combobox(container_frame, textvariable=self.category_var, font=self.base_font,
                                         values=["购物", "医疗", "娱乐", "学习", "生活"], state="readonly")
        category_combobox.grid(row=2, column=1, padx=5, pady=5, sticky=tk.EW)

        # 金额输入
        self.amount_var = tk.StringVar()
        amount_entry = ttk.Entry(container_frame, textvariable=self.amount_var, font=self.mono_font)
        amount_entry.grid(row=3, column=1, padx=5, pady=5, sticky=tk.EW)

        # 事项输入
        self.description_var = tk.StringVar()
        description_entry = ttk.Entry(container_frame, textvariable=self.description_var, font=self.base_font)
        description_entry.grid(row=4, column=1, padx=5, pady=5, sticky=tk.EW)

        # 添加按钮
        add_button = ttk.Button(container_frame, text="添加记录", command=self.add_record)
        add_button.grid(row=5, column=0, columnspan=2, pady=12)

        # 配置列权重
        container_frame.columnconfigure(1, weight=1)

        # 最近记录表格
        columns = ("日期", "类型", "分类", "金额", "事项")
        self.recent_tree = ttk.Treeview(recent_frame, columns=columns, show="headings")

        # 设置列宽和标题
        col_widths = [100, 80, 80, 90, 200]  # 调整日期列宽度
        for col, width in zip(columns, col_widths):
            self.recent_tree.heading(col, text=col, anchor=tk.CENTER)
            self.recent_tree.column(col, width=width, anchor=tk.CENTER)

        # 设置表格样式
        style = ttk.Style()
        style.configure("Treeview.Heading", font=('Microsoft YaHei', 9, 'bold'), background="#FFE6EE")
        style.configure("Treeview", font=self.base_font, rowheight=25, background="white")

        # 添加滚动条
        scrollbar = ttk.Scrollbar(recent_frame, orient=tk.VERTICAL, command=self.recent_tree.yview)
        self.recent_tree.configure(yscroll=scrollbar.set)
        scrollbar.grid(row=0, column=1, sticky=tk.NS)

        # 使用grid布局管理表格
        self.recent_tree.grid(row=0, column=0, sticky=tk.NSEW)

        # 配置最近记录框架的行列权重
        recent_frame.columnconfigure(0, weight=1)
        recent_frame.rowconfigure(0, weight=1)

        # 加载最近记录
        self.load_recent_records()

    def show_date_calendar(self):
        """显示日期选择日历"""

        def on_date_select():
            self.date_var.set(cal.get_date())
            top.destroy()

        # 创建日历弹出窗口
        top = tk.Toplevel(self.root)
        top.title("选择日期")
        top.geometry("320x260")
        top.grab_set()

        # 创建日历控件
        cal = Calendar(top, selectmode='day', date_pattern='y-mm-dd')
        cal.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

        # 添加选择按钮
        btn_frame = ttk.Frame(top)
        btn_frame.pack(pady=5)

        ttk.Button(btn_frame, text="确定", command=on_date_select).pack(side=tk.LEFT, padx=10)
        ttk.Button(btn_frame, text="取消", command=top.destroy).pack(side=tk.LEFT, padx=10)

    def create_query_tab(self):
        """创建查账标签页"""
        # 查询条件框架
        filter_frame = ttk.LabelFrame(self.query_frame, text="查询条件")
        filter_frame.pack(fill=tk.X, padx=10, pady=10)

        # 使用Frame作为容器
        container_frame = ttk.Frame(filter_frame)
        container_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

        # 开始时间
        ttk.Label(container_frame, text="开始日期:", font=self.base_font).grid(row=0, column=0,
                                                                               padx=5, pady=8,
                                                                               sticky=tk.W)
        self.start_var = tk.StringVar(value="2023-01-01")

        # 开始日期选择器
        start_frame = ttk.Frame(container_frame)
        start_frame.grid(row=0, column=1, padx=5, pady=8, sticky=tk.W)
        self.start_entry = ttk.Entry(start_frame, textvariable=self.start_var, font=self.base_font, width=12)
        self.start_entry.pack(side=tk.LEFT, padx=(0, 5), fill=tk.X, expand=True)
        ttk.Button(start_frame, text="选择", width=5,
                   command=lambda: self.show_date_calendar_query("start")).pack(side=tk.RIGHT)

        # 结束时间
        ttk.Label(container_frame, text="结束日期:", font=self.base_font).grid(row=0, column=2,
                                                                               padx=5, pady=8,
                                                                               sticky=tk.W)
        self.end_var = tk.StringVar(value=datetime.now().strftime("%Y-%m-%d"))

        # 结束日期选择器
        end_frame = ttk.Frame(container_frame)
        end_frame.grid(row=0, column=3, padx=5, pady=8, sticky=tk.W)
        self.end_entry = ttk.Entry(end_frame, textvariable=self.end_var, font=self.base_font, width=12)
        self.end_entry.pack(side=tk.LEFT, padx=(0, 5), fill=tk.X, expand=True)
        ttk.Button(end_frame, text="选择", width=5,
                   command=lambda: self.show_date_calendar_query("end")).pack(side=tk.RIGHT)

        # 查询按钮
        query_button = ttk.Button(container_frame, text="查询", command=self.query_records)
        query_button.grid(row=0, column=4, padx=15, pady=8)

        # 统计结果显示
        stats_frame = ttk.Frame(self.query_frame)
        stats_frame.pack(fill=tk.X, padx=10, pady=10)

        # 总收入
        ttk.Label(stats_frame, text="总收入:", font=self.header_font).pack(side=tk.LEFT, padx=15)
        self.income_var = tk.StringVar(value="0.00")
        ttk.Label(stats_frame, textvariable=self.income_var, font=('Microsoft YaHei', 12, 'bold'),
                  foreground="#2E7D32").pack(side=tk.LEFT, padx=5)

        # 总支出
        ttk.Label(stats_frame, text="总支出:", font=self.header_font).pack(side=tk.LEFT, padx=15)
        self.expense_var = tk.StringVar(value="0.00")
        ttk.Label(stats_frame, textvariable=self.expense_var, font=('Microsoft YaHei', 12, 'bold'),
                  foreground="#C62828").pack(side=tk.LEFT, padx=5)

        # 结余
        ttk.Label(stats_frame, text="结余:", font=self.header_font).pack(side=tk.LEFT, padx=15)
        self.balance_var = tk.StringVar(value="0.00")
        balance_label = ttk.Label(stats_frame, textvariable=self.balance_var,
                                  font=('Microsoft YaHei', 12, 'bold'), foreground="#1565C0")
        balance_label.pack(side=tk.LEFT, padx=5)

        # 创建分页显示收入和支出
        self.query_notebook = ttk.Notebook(self.query_frame)
        self.query_notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 收入分页
        income_frame = ttk.Frame(self.query_notebook)
        self.query_notebook.add(income_frame, text="收入记录")

        # 支出分页
        expense_frame = ttk.Frame(self.query_notebook)
        self.query_notebook.add(expense_frame, text="支出记录")

        # 设置表格样式
        style = ttk.Style()
        style.configure("Treeview.Heading", font=('Microsoft YaHei', 9, 'bold'), background="#FFE6EE")
        style.configure("Treeview", font=self.base_font, rowheight=25, background="white")

        # 创建收入表格
        columns = ("日期", "分类", "金额", "事项")
        self.income_tree = ttk.Treeview(income_frame, columns=columns, show="headings", height=10)

        col_widths = [100, 100, 100, 300]
        for col, width in zip(columns, col_widths):
            self.income_tree.heading(col, text=col, anchor=tk.CENTER)
            self.income_tree.column(col, width=width, anchor=tk.CENTER)

        scrollbar_income = ttk.Scrollbar(income_frame, orient=tk.VERTICAL, command=self.income_tree.yview)
        self.income_tree.configure(yscroll=scrollbar_income.set)
        self.income_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar_income.pack(side=tk.RIGHT, fill=tk.Y)

        # 创建支出表格
        self.expense_tree = ttk.Treeview(expense_frame, columns=columns, show="headings", height=10)

        for col, width in zip(columns, col_widths):
            self.expense_tree.heading(col, text=col, anchor=tk.CENTER)
            self.expense_tree.column(col, width=width, anchor=tk.CENTER)

        scrollbar_expense = ttk.Scrollbar(expense_frame, orient=tk.VERTICAL, command=self.expense_tree.yview)
        self.expense_tree.configure(yscroll=scrollbar_expense.set)
        self.expense_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar_expense.pack(side=tk.RIGHT, fill=tk.Y)

    def show_date_calendar_query(self, field):
        """显示查询日期选择日历"""

        def on_date_select():
            date = cal.get_date()
            if field == "start":
                self.start_var.set(date)
            else:
                self.end_var.set(date)
            top.destroy()

        # 创建日历弹出窗口
        top = tk.Toplevel(self.root)
        top.title("选择日期")
        top.geometry("320x260")
        top.grab_set()

        # 创建日历控件
        cal = Calendar(top, selectmode='day', date_pattern='y-mm-dd')
        cal.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

        # 添加选择按钮
        btn_frame = ttk.Frame(top)
        btn_frame.pack(pady=5)

        ttk.Button(btn_frame, text="确定", command=on_date_select).pack(side=tk.LEFT, padx=10)
        ttk.Button(btn_frame, text="取消", command=top.destroy).pack(side=tk.LEFT, padx=10)

    def create_about_tab(self):
        """创建关于标签页"""
        about_text = """
        个人记账本 v1.1

        功能说明：
        1. 记账功能：记录收支情况，包括日期、类型、分类、金额和事项
        2. 查账功能：按时间段查询收支记录，统计总收入和总支出

        使用说明：
        - 在"记账"标签页中添加新的收支记录
        - 在"查账"标签页中设置日期范围并查询记录
        - 收入和支出分别显示在不同的标签页中

        开发信息：
        - 开发语言：Python
        - GUI库：Tkinter
        - 数据存储：CSV文件

        © 2025 个人记账本
        """

        about_frame = ttk.Frame(self.about_frame)
        about_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)

        about_label = tk.Label(about_frame, text=about_text, justify=tk.LEFT,
                               font=('Microsoft YaHei', 10), padx=20, pady=20,
                               bg="#FFE6EE", fg="black")
        about_label.pack(fill=tk.BOTH, expand=True)

    def add_record(self):
        """添加新记录到CSV文件"""
        # 获取输入值
        date = self.date_var.get()
        record_type = self.type_var.get()
        category = self.category_var.get()
        amount = self.amount_var.get()
        description = self.description_var.get()

        # 验证输入
        if not date or not record_type or not category or not amount or not description:
            messagebox.showerror("错误", "所有字段都必须填写！")
            return

        try:
            # 验证日期格式
            datetime.strptime(date, "%Y-%m-%d")
        except ValueError:
            messagebox.showerror("错误", "日期格式不正确！请使用YYYY-MM-DD格式。")
            return

        try:
            amount_val = float(amount)
            if amount_val <= 0:
                messagebox.showerror("错误", "金额必须大于0！")
                return
        except ValueError:
            messagebox.showerror("错误", "金额必须是数字！")
            return

        # 写入CSV文件
        with open(self.filename, 'a', newline='', encoding='utf-8') as file:
            writer = csv.writer(file)
            writer.writerow([date, record_type, category, amount, description])

        # 清空输入框
        self.amount_var.set("")
        self.description_var.set("")

        # 更新最近记录
        self.load_recent_records()

        messagebox.showinfo("成功", "记录已成功添加！")

    def load_recent_records(self):
        """加载最近5条记录"""
        # 清空现有数据
        for item in self.recent_tree.get_children():
            self.recent_tree.delete(item)

        try:
            with open(self.filename, 'r', encoding='utf-8') as file:
                reader = csv.reader(file)
                next(reader)  # 跳过标题行
                records = list(reader)

                # 获取最后5条记录（最新的）
                for record in records[-5:]:
                    # 金额格式化为保留两位小数
                    try:
                        record[3] = f"{float(record[3]):.2f}"
                    except ValueError:
                        pass
                    self.recent_tree.insert("", tk.END, values=record)
        except FileNotFoundError:
            pass

    def query_records(self):
        """查询指定时间范围内的记录"""
        # 清空现有数据
        for item in self.income_tree.get_children():
            self.income_tree.delete(item)
        for item in self.expense_tree.get_children():
            self.expense_tree.delete(item)

        # 获取查询条件
        start_date = self.start_var.get()
        end_date = self.end_var.get()

        # 验证日期格式
        try:
            start = datetime.strptime(start_date, "%Y-%m-%d")
            end = datetime.strptime(end_date, "%Y-%m-%d")
        except ValueError:
            messagebox.showerror("错误", "日期格式不正确！请使用YYYY-MM-DD格式。")
            return

        if start > end:
            messagebox.showerror("错误", "开始日期不能晚于结束日期！")
            return

        # 初始化统计变量
        total_income = 0.0
        total_expense = 0.0

        try:
            with open(self.filename, 'r', encoding='utf-8') as file:
                reader = csv.reader(file)
                headers = next(reader)  # 跳过标题行

                # 检查列数是否正确
                if len(headers) < 5:
                    messagebox.showerror("错误", "数据文件格式不正确！")
                    return

                for row in reader:
                    if len(row) < 5:
                        continue

                    try:
                        # 从记录中提取日期
                        record_date = datetime.strptime(row[0], "%Y-%m-%d")
                    except ValueError:
                        # 如果日期解析失败，跳过这条记录
                        continue

                    # 检查是否在时间范围内
                    if start <= record_date <= end:
                        record_type = row[1]
                        category = row[2]

                        try:
                            amount = float(row[3])
                        except ValueError:
                            amount = 0.0

                        description = row[4]

                        # 添加到相应表格并更新统计
                        if record_type == "收入":
                            self.income_tree.insert("", tk.END, values=(
                                row[0], category, f"{amount:.2f}", description
                            ))
                            total_income += amount
                        else:  # 支出
                            self.expense_tree.insert("", tk.END, values=(
                                row[0], category, f"{amount:.2f}", description
                            ))
                            total_expense += amount

        except FileNotFoundError:
            messagebox.showerror("错误", "找不到数据文件！")
            return

        # 更新统计信息
        self.income_var.set(f"{total_income:.2f}")
        self.expense_var.set(f"{total_expense:.2f}")
        self.balance_var.set(f"{total_income - total_expense:.2f}")


if __name__ == "__main__":
    root = tk.Tk()
    app = AccountingApp(root)
    root.mainloop()